home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Snippets / Toolbox / ProgressBars 1.0 / Sources / ThreadedProgress.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-17  |  7.0 KB  |  291 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        ThreadedProgress.c
  3.  
  4.     Contains:    Progress bar implementation using the Thread Manager
  5.  
  6.     Written by:    Chris White, Developer Technical Support
  7.     
  8.     Copyright:    © 1996 by Apple Computer, Inc., all rights reserved.
  9.     
  10.     Change History (most recent first):
  11.     
  12.             1/22/96            CW        First release
  13.  
  14. */
  15.  
  16.  
  17. #pragma segment Core
  18.  
  19.  
  20. // System Includes
  21.  
  22.  
  23. #include <Threads.h>
  24.  
  25.  
  26.  
  27. // Application includes
  28.  
  29. #ifndef __BAREBONES__
  30.     #include "BareBones.h"
  31. #endif
  32.  
  33. #ifndef __PROTOTYPES__
  34.     #include "Prototypes.h"
  35. #endif
  36.  
  37.  
  38. // static prototypes
  39.  
  40. static pascal void* ProgressDialogThread ( tThreadedOperationPtr theInfo );
  41. static pascal void    ThreadTermination ( ThreadID threadTerminated, void* terminationProcParam );
  42.  
  43.  
  44.  
  45.  
  46.  
  47. OSErr ThreadedProgressOperation ( tThreadedOperation theOperation, void* refCon,
  48.                     StringPtr theText, SInt32* operationErr, Boolean bBarberPole )
  49. {
  50.     OSErr                    theErr = noErr;
  51.     ThreadID                operationsThreadID = 0;
  52.     ThreadID                progressDlgThreadID = 0;
  53.     tThreadedOperationPtr    theInfo = nil;
  54.     
  55.     
  56.     
  57.     theInfo = (tThreadedOperationPtr) NewPtrClear ( sizeof ( tThreadedOperationRec ) );
  58.     theErr = MemError ( );
  59.     if ( theErr )    goto CleanupAndbail;
  60.     
  61.     BlockMoveData ( theText, theInfo->theText, theText[0] + 1 );
  62.     theInfo->bBarberPole = bBarberPole;
  63.     theInfo->refCon = refCon;
  64.     
  65.     
  66.     // Create the Progress Dialog Thread
  67.     theErr = NewThread ( kCooperativeThread, (ThreadEntryProcPtr) ProgressDialogThread,
  68.                             (void*) theInfo, kDefaultStackSpace, kNoCreationOptions,
  69.                             (void*) operationErr, &progressDlgThreadID );
  70.     if ( theErr )    goto CleanupAndbail;
  71.     
  72.     // Install termination routine to decrement the usage count
  73.     // and maybe dispose of the tThreadedOperationRec.
  74.     theInfo->usageCount++;
  75.     theErr = SetThreadTerminator ( progressDlgThreadID, ThreadTermination, (void*) theInfo );
  76.  
  77.     // Create the Operation Thread 
  78.     theErr = NewThread ( kCooperativeThread, (pascal void* (*) (void*)) theOperation, (void*) theInfo,
  79.                             kDefaultStackSpace, kNoCreationOptions, (void*) operationErr,
  80.                             &operationsThreadID );
  81.     if ( theErr )    goto CleanupAndbail;
  82.     
  83.     theInfo->usageCount++;
  84.     theErr = SetThreadTerminator ( operationsThreadID, ThreadTermination, (void*) theInfo );
  85.     
  86.     // Get the dialog drawn _before_ the actual operation is started
  87.     theErr = YieldToThread ( progressDlgThreadID );
  88.     if ( theErr )    goto CleanupAndbail;
  89.  
  90.     return noErr;
  91.     
  92. CleanupAndbail:
  93.     
  94.     if ( theInfo )
  95.         DisposePtr ( (Ptr) theInfo );
  96.         
  97.     // Dispose of the threads, and pass the error codes back
  98.     if ( operationsThreadID )
  99.         DisposeThread ( operationsThreadID, (void*) theErr, false );
  100.     
  101.     if ( operationsThreadID )
  102.         DisposeThread ( progressDlgThreadID, (void*) theErr, false );
  103.     
  104.     return theErr;
  105. }
  106.  
  107.  
  108.  
  109. static pascal void* ProgressDialogThread ( tThreadedOperationPtr theInfo )
  110. {
  111.     SInt16        theType;
  112.     GrafPtr        savePort;
  113.     DialogRef    theDialog = nil;
  114.     Handle        theHan;
  115.     Rect        theRect;
  116.     
  117.     
  118.     theDialog = GetNewDialog ( kProgressDialogID, nil, (WindowPtr) -1 );
  119.     
  120.     SetWRefCon ( theDialog, (long) theInfo );
  121.     
  122.     GetDialogItem ( theDialog, kStaticTextItemID, &theType, &theHan, &theRect );
  123.     SetDialogItemText ( theHan, theInfo->theText );
  124.     
  125.     GetDialogItem ( theDialog, kUserItemID, &theType, &theHan, &theRect );
  126.     if ( !theInfo->bBarberPole )
  127.     {
  128.         SetDialogItem ( theDialog, kUserItemID, theType, (Handle) gOutlineUserItemUPP, &theRect );
  129.         CallUserItemProc ( gOutlineUserItemUPP, theDialog, kUserItemID );
  130.     }
  131.     
  132.     ShowWindow ( theDialog );
  133.     DrawDialog ( theDialog );
  134.     
  135.     
  136.     while ( theInfo->bCancelled == false )
  137.     {
  138.         YieldToAnyThread ( );
  139.         
  140.         // Although the user interface doesn't allow you to execute
  141.         // more than one threaded progress bar, we'll be careful to
  142.         // support it here. It's just a case of making sure the port
  143.         // is setup and restored across calls to YieldToAnyThread.
  144.         
  145.         GetPort ( &savePort );
  146.         SetPort ( theDialog );
  147.         
  148.         if ( theInfo->bBarberPole )
  149.         {
  150.             PicHandle        thePic;
  151.             static SInt16    theID = 1000;        // Gotcha: Non-reentrant, see documentation
  152.             
  153.             
  154.             // Gotcha: Some Resource Manager calls can only be made
  155.             // from the main thread on a Mac Plus. See documentation
  156.             thePic = GetPicture ( theID++ );
  157.             DrawPicture ( thePic, &theRect );
  158.             if ( theID > 1003 )
  159.                 theID = 1000;
  160.             
  161.             if ( theInfo->doneAmount == kBarberPoleFinished )
  162.                 break;
  163.         }
  164.         else
  165.         {
  166.             if ( theInfo->doneAmount != theInfo->drawnAmount )
  167.             {
  168.                 int        theLength;
  169.                 float    floatDone, floatMax, thePercent;
  170.                 
  171.                 // Temporarily adjust the user item rect to draw the bar
  172.                 GetDialogItem ( theDialog, kUserItemID, &theType, &theHan, &theRect );
  173.                 theLength = theRect.right - theRect.left;
  174.                 floatDone = theInfo->doneAmount;
  175.                 floatMax = theInfo->maxAmount;
  176.                 thePercent = (floatDone / floatMax) * 100;
  177.                 theRect.right = theRect.left + ((thePercent / 100) * theLength);
  178.                 
  179.                 theRect.top--; theRect.bottom++;
  180.                 FillRect ( &theRect, &qd.black );
  181.             }
  182.             
  183.             if ( theInfo->doneAmount == theInfo->maxAmount )
  184.                 break;
  185.         }
  186.         
  187.         SetPort ( savePort );
  188.     }
  189.     
  190.     // A problem occurs if the thread is terminated before the dialog is
  191.     // disposed. Fortunatly, with the current implementation, it can't.
  192.     // However, if this can occur with your implementation, you'll want
  193.     // to dispose of the dialog and (optionally?) restore the port in the
  194.     // termination routine.
  195.     DisposeDialog ( theDialog );
  196.     
  197.     return noErr;
  198. }
  199.  
  200.  
  201.  
  202. //
  203. // We don't want to dispose of the record when another thread could still
  204. // be accessing it. Although they'll both finish about the same time, we
  205. // don't want to rely on the implementation of the thread scheduler. This
  206. // approach ensures both threads have finished with the record.
  207. //
  208. static pascal void ThreadTermination ( ThreadID threadTerminated, void* terminationProcParam )
  209. {
  210.     OSErr    theErr;
  211.     
  212.     
  213.     #if DEBUGGING
  214.     if ( terminationProcParam == nil )
  215.         DebugStr ( "\p ThreadTermination: terminationProcParam is nil" );
  216.     #endif
  217.     
  218.     
  219.     ((tThreadedOperationPtr) terminationProcParam)->usageCount--;
  220.     if ( ((tThreadedOperationPtr) terminationProcParam)->usageCount == 0 )
  221.     {
  222.         DisposePtr ( (Ptr) terminationProcParam );
  223.         
  224.         #if DEBUGGING
  225.         theErr = MemError ( );
  226.         if ( theErr )    DebugStrNum ( "\p ThreadTermination: DisposePtr", theErr );
  227.         #endif
  228.     }
  229.     
  230.     return;
  231. }
  232.  
  233.  
  234.  
  235. //
  236. // This routine is one of the operations carried out
  237. // which the progress bar is representing.
  238. //
  239. pascal SInt32 ThreadedStandardDemoOperation ( tThreadedOperationPtr theInfo )
  240. {
  241.     OSErr        theErr = noErr;
  242.     int            i;
  243.     const int    max = 100;
  244.     
  245.     
  246.     for ( i = 1; i <= max && theInfo->bCancelled == false; i++ )
  247.     {
  248.         SInt32    theDelay = 10L;
  249.         Delay ( theDelay, &theDelay );
  250.         
  251.         theInfo->doneAmount = i;
  252.         theInfo->maxAmount = max;
  253.         
  254.         YieldToAnyThread ( );
  255.     }
  256.     
  257.     return (SInt32) theErr;
  258. }
  259.  
  260.  
  261.  
  262. //
  263. // This routine is one of the operations carried out
  264. // which the progress bar is representing.
  265. //
  266. pascal SInt32 ThreadedBarberPoleDemoOperation ( tThreadedOperationPtr theInfo )
  267. {
  268.     // A5 is not garanteed to be valid
  269.     
  270.     OSErr        theErr = noErr;
  271.     int            i;
  272.     const int    max = 100;
  273.     
  274.     
  275.     for ( i = 1; i <= max && theInfo->bCancelled == false; i++ )
  276.     {
  277.         SInt32    theDelay = 10L;
  278.         Delay ( theDelay, &theDelay );
  279.         
  280.         YieldToAnyThread ( );
  281.     }
  282.     
  283.     theInfo->doneAmount = kBarberPoleFinished;
  284.     
  285.     return (SInt32) theErr;
  286. }
  287.  
  288.  
  289.  
  290.  
  291.